﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TileopiaUI_1_0
{
    public partial class Minesweeper : System.Web.UI.Page
    {

        public World w = null;
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Session["world"] == null)
            {
                Random r = new Random();
                w = new World(r.Next());
                Session["world"] = w;
            }
            else
            {
                w = (World)Session["world"];
            }
        }
    }

    public class World
    {
        private int id;
        private Random rand;
        public int Id
        {
            get { return id; }
        }
        private Tile[,] tiles;
        public int rows;
        public int cols;
        public int mineCount;
        private List<int> mines;
        private ActionList actions;
        public Tile GetTile(int row, int col)
        {
            return tiles[row, col];
        }

        public void GenerateWorld(int seed)
        {
            this.id = seed;
            this.rand = new Random(this.id);
            this.rows = 11;
            this.cols = 11;
            this.mineCount = 15;
            this.tiles = new Tile[rows, cols];
            this.mines = new List<int>();
            for (int i = 0; i < mineCount; i++)
            {
                int mineLocation = rand.Next(rows * cols);
                if (mines.Contains(mineLocation))
                {
                    i--;
                }
                else
                {
                    mines.Add(mineLocation);
                }
            }
            for (int row = 0; row < this.rows; row++)
            {
                for (int col = 0; col < this.cols; col++)
                {
                    if (mines.Contains((row * cols) + col))
                    {
                        // I am a mine!!!
                        this.tiles[row, col] = new Tile(row, col, "blank", "something");
                    }
                    else
                    {
                        // 1  2  3
                        // 4  X  6
                        // 7  8  9
                        int bombCount = 0;
                        if (row != 0)
                        {
                            // 1
                            if (col != 0)
                            {
                                bombCount += (mines.Contains(((row - 1) * cols) + (col - 1)) ? 1 : 0);
                            }
                            // 2
                            bombCount += (mines.Contains(((row - 1) * cols) + (col)) ? 1 : 0);
                            // 3
                            if (col != (this.cols - 1))
                            {
                                bombCount += (mines.Contains(((row - 1) * cols) + (col + 1)) ? 1 : 0);
                            }
                        }
                        // 4
                        if (col != 0)
                        {
                            bombCount += (mines.Contains(((row) * cols) + (col - 1)) ? 1 : 0);
                        }
                        // 6
                        if (col != (this.cols - 1))
                        {
                            bombCount += (mines.Contains(((row) * cols) + (col + 1)) ? 1 : 0);
                        }
                        if (row != (this.rows - 1))
                        {
                            // 7
                            if (col != 0)
                            {
                                bombCount += (mines.Contains(((row + 1) * cols) + (col - 1)) ? 1 : 0);
                            }
                            // 8
                            bombCount += (mines.Contains(((row + 1) * cols) + (col)) ? 1 : 0);
                            // 9
                            if (col != (this.cols - 1))
                            {
                                bombCount += (mines.Contains(((row + 1) * cols) + (col + 1)) ? 1 : 0);
                            }
                        }
                        this.tiles[row, col] = new Tile(row, col, "blank", bombCount.ToString());
                    }
                    this.tiles[row, col].AddAction(new MineSweeperAction("T", 0, row, col));
                    this.tiles[row, col].AddAction(new MineSweeperAction("T", 1, row, col));
                }
            }
            this.actions = new ActionList();
        }
        public World(int seed)
        {
            GenerateWorld(seed);
        }
        public void ProcessAction(string actionInfo)
        {
            string[] a = actionInfo.Split(new Char[] { '*' }, 2);
            if (a[0] == "T")
            {
                string[] f = a[1].Split(new Char[] { '-' }, 4);
                int row = int.Parse(f[0]);
                int col = int.Parse(f[1]);
                int actionId = int.Parse(f[2]);
                string actionText = "";
                if (f.Length == 4)
                {
                    actionText = f[3];
                }
                this.GetTile(row, col).ProcessAction(actionId, actionText, this);
            }
            else if(a[0]=="A")
            {
                string[] f = a[1].Split(new Char[] { '-' }, 2);
                int actionId = int.Parse(f[0]);
                string actionText = "";
                if (f.Length == 2)
                {
                    actionText = f[1];
                }
                this.actions.ProcessAction(actionId, actionText, this);
            }
        }
        public override string ToString()
        {
            //{
            //    'id':1,
            //    'tiles':[
            //        {'row':[
            string ret = "{'id':" + this.id + "," + "\r\n";
            ret += "   'tiles':[" + "\r\n";
            for (int row = 0; row < this.rows; row++)
            {
                ret += "      {'row':[" + "\r\n";
                for (int col = 0; col < this.cols; col++)
                {
                    ret += "          " + this.tiles[row, col].ToString() + ((col != this.cols - 1) ? "," : "") + "\r\n";
                }
                ret += "      ]}" + ((row != this.rows - 1) ? "," : "") + "\r\n";
            }
            ret += "]\r\n";
            if (this.actions.Count > 0)
            {
                ret += ", " + this.actions.ToString();
            }
            ret += "}" + "\r\n";
            return ret;
        }

        internal void AddAction(Action action)
        {
            actions.AddAction(action);
        }
    }
    public class Tile
    {
        public int row;
        public int col;
        public string background;
        public string image;
        private ActionList actions;

        public int State = 0;

        public Tile(int row, int col, string background, string image)
        {
            this.row = row;
            this.col = col;
            this.background = background;
            this.image = image;
            this.actions = new ActionList();
        }
        public void AddAction(Action a)
        {
            this.actions.AddAction(a);
        }
        public override string ToString()
        {
            //{row: 0, col:  0, 'background':'blank', 'image':'blank'},
            string ret = "{";
            ret += "'row': " + this.row.ToString() + ", 'col': " + this.col.ToString() + "";
            ret += ", 'background':'" + this.background + "'";
            ret += ", 'image':'" + ((this.State == 0) ? "q" : ((this.State == 1) ? "flag" : this.image)) + "'";
            if (this.actions.Count > 0)
            {
                ret += ", " + this.actions.ToString();
            }
            ret += "}";
            return ret;
        }

        public void ProcessAction(int actionId, string actionInfo, World w)
        {
            this.actions.ProcessAction(actionId, actionInfo, w);
        }

        public void RemoveAction(int i)
        {
            this.actions.RemoveAction(i);
        }

        public void ClearActions()
        {
            this.actions.ClearActions();
        }
    }
    public class ActionList
    {
        private List<Action> actions = null;
        public int Count
        {
            get { return this.actions.Count; }
        }
        public ActionList()
        {
            this.actions = new List<Action>();
        }
        public void AddAction(Action a)
        {
            actions.Add(a);
        }
        public void RemoveAction(int i)
        {
            actions.RemoveAt(i);
        }
        public override string ToString()
        {
            //    'actions':[
            //        {'actionType':'general', 'display': 'Reset', 'id': ''},
            //        {'actionType':'general', 'display': 'Remove Tile Action', 'id': '1'},
            //    ]
            if (this.actions.Count == 0)
            {
                return "";
            }
            else
            {
                string actionText = "";
                foreach (Action a in this.actions)
                {
                    if (actionText != "")
                    {
                        actionText += ", ";
                    }
                    actionText += a.ToString();
                }
                return "'actions':[" + actionText + "]";
            }
        }

        public void ProcessAction(int actionId, string actionInfo, World w)
        {
            this.actions[actionId].ProcessAction(actionInfo, w);
        }

        public void ClearActions()
        {
            this.actions.Clear();
        }
    }
    public class Action
    {
        protected string display;
        protected string id;
        public Action(string display, string id)
        {
            this.display = display;
            this.id = id;
        }
        public override string ToString()
        {
            //{'actionType':'general', 'display': 'Reset', 'id': ''},
            return "{'actionType':'general', 'display': '" + this.display + "', 'id': 'action=" + this.id + "'}";
        }

        public virtual void ProcessAction(string actionInfo, World w)
        {
        }

    }
    public class MineSweeperAction : Action
    {
        protected string actionType;
        protected int actionNumber;
        protected int row;
        protected int col;
        public MineSweeperAction(string actionType, int actionNumber, int row, int col)
            : base((actionNumber == 0) ? "Click" : ((actionNumber==1)?"Flag as mine":"New Game"), actionType+"*" + row + "-" + col + "-" + actionNumber)
        {
            this.actionType = actionType;
            this.actionNumber = actionNumber;
            this.row = row;
            this.col = col;
        }
        public override void ProcessAction(string actionInfo, World w)
        {
            Tile t = w.GetTile(row, col);
            if (actionNumber==0)
            {
                t.State = 2;
                t.ClearActions();
                if (t.image == "0")
                {
                    ClearBlankSpace(w, row, col);
                }
                else if (t.image == "something")
                {
                    // game over man!!
                    GameOver(w);
                }
            }
            else if(actionNumber==1)
            {
                t.State = 1;
            }
            else if (actionNumber == 2)
            {
                Random r = new Random();
                w.GenerateWorld(r.Next());
            }
        }
        private void ClearBlankSpace(World w, int row, int col)
        {
            bool valid;
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    valid = true;
                    if (row + i == -1) valid = false;
                    if (row + i == w.rows) valid = false;
                    if (col + j == -1) valid = false;
                    if (col + j == w.cols) valid = false;
                    if (valid)
                    {
                        Tile t = w.GetTile(row + i, col + j);
                        if (t.State == 0)
                        {
                            t.State = 2;
                            t.ClearActions();
                            if (t.image == "0")
                            {
                                ClearBlankSpace(w, row + i, col + j);
                            }
                        }
                    }
                }
            }
        }
        private void GameOver(World w)
        {
            for (row = 0; row < w.rows; row++)
            {
                for (col = 0; col < w.cols; col++)
                {
                    w.GetTile(row, col).ClearActions();
                }
            }
            w.AddAction(new MineSweeperAction("A", 2, 0, 0));
        }
    }
}